<script lang="ts" setup>
import _ from "lodash";
import { whitelist as whitelistRaw } from "~/config/whitelist.json";
import { getTxByPair } from "~/util";
import DataBuilder from "~/util/DataBuilder";
import {
  useProvider,
  // MetamaskProvider,
} from "~/util/ethers_manager";
import Loading from "./vloading.vue";
// import Sidebar from "./sidebar.vue";
import { ethers } from "ethers";
// import config from "~/config";
import { usePrice } from '~/util'
import audioSrc from '~/assets/Horn.mp3'
import themeManager from "~/util/theme_manager";
import { RtPairInfo } from "~/models";
import IPairTxData, { IBasicTx } from "~/models/IData";

const theme = themeManager.getTheme()
// const router = useRouter()

const props = defineProps<{
  provider: string,
  tokenAddress: string,
  baseAddress: string,
  pairAddress: string,
  active: boolean,
  graphql: string,
  scan: string,
}>()


const TABS = ["All", "Swaps", "Adds", "Removes", "Swaps0In", "Swaps1In"]
const WHITELIST = whitelistRaw.map((item) => item.toLowerCase())

const tabIndex = ref(0)
const pairInfo = ref(null as (RtPairInfo | null))
const txData = ref(null as (IPairTxData | null))
const token0 = ref("-")
const token1 = ref("-")
const token0Addr = ref("-")
const token1Addr = ref("-")
const pool0 = ref(0)
const pool1 = ref(0)
const t0FlowIn = ref(0)
const t0FlowOut = ref(0)
const t0FlowWhiteList = ref(0)
const t1FlowIn = ref(0)
const t1FlowOut = ref(0)
const t1FlowWhiteList = ref(0)
const price = ref(0)
const price_usd = ref(0)
const detailed = ref(false)
const audioRef = ref(null as any)

const tdStyle = computed(() => {
  return {
    "border-top-color": theme.getColor(0),
  };
})

const baseTokenName = computed(() => {
  
  if (
    !token0Addr.value ||
    !token1Addr.value ||
    !token0.value ||
    !token1.value ||
    !props.baseAddress
  ) {
    return "-";
  }
  return ethers.utils.getAddress(props.baseAddress) ==
    ethers.utils.getAddress(token0Addr.value)
    ? token0.value
    : token1.value;
})

const poolPrice = computed(() => {
  if (token0.value == baseTokenName.value) {
    return (pool0.value / pool1.value) * price.value;
  } else if (token1.value == baseTokenName.value) {
    return (pool1.value / pool0.value) * price.value;
  } else {
    return null;
  }
})

const swaps = computed(() => {
  if (!txData.value) {
    return []
  }
  return txData.value.swaps;
})

const adds = computed(() => {
  if (!txData.value) {
    return []
  }
  return txData.value.mints;
})

const removes = computed(() => {
  if (!txData.value) {
    return []
  }
  return txData.value.burns;
})


const all = computed(() => {
  return (swaps.value as IBasicTx[])
    .concat(adds.value as IBasicTx[])
    .concat(removes.value as IBasicTx[])
    .sort((a: any, b: any) => b.transaction.timestamp - a.transaction.timestamp);
})

const swaps0In = computed(() => {
  return swaps.value.filter((item: any) => item.amount0In > 0);
})

const swaps1In = computed(() => {
  return swaps.value.filter((item: any) => item.amount1In > 0);
})

// const t1Flow = computed(() => {
//   return t1FlowIn.value - t1FlowOut.value;
// })

// const t0Flow = computed(() => {
//   return t0FlowIn.value - t0FlowOut.value;
// })

const list = computed(() => {
  return (
    ({
      Swaps: swaps.value,
      Adds: adds.value,
      Removes: removes.value,
      All: all.value,
      Swaps0In: swaps0In.value,
      Swaps1In: swaps1In.value,
    } as any)[TABS[tabIndex.value]] || []
  );
})

const poolPriceUSD = computed(() => {
  if (token0.value == baseTokenName.value) {
    return (pool0.value / pool1.value) * price_usd.value;
  } else if (token1.value == baseTokenName.value) {
    return (pool1.value / pool0.value) * price_usd.value;
  } else {
    return null;
  }
})

// const lastTxPrice = computed(() => {
//   if (!txData.value) {
//     return 0;
//   }
//   const swaps = txData.value.swaps;
//   if (!swaps || swaps.length === 0) {
//     return;
//   }
//   const lastTx = swaps[swaps.length - 1];

//   if (token0.value === baseTokenName.value) {
//     if (parseFloat(lastTx.amount1In) > 0) {
//       return lastTx.amount0Out / lastTx.amount1In;
//     } else if (parseFloat(lastTx.amount1Out) > 0) {
//       return lastTx.amount0In / lastTx.amount1Out;
//     } else {
//       return null;
//     }
//   } else if (token1.value === "ETH") {
//     if (parseFloat(lastTx.amount0In) > 0) {
//       return lastTx.amount1Out / lastTx.amount0In;
//     } else if (parseFloat(lastTx.amount0Out) > 0) {
//       return lastTx.amount1In / lastTx.amount0Out;
//     } else {
//       return null;
//     }
//   } else {
//     return null;
//   }
// })

const initPrice = computed(() => {
  if (!txData.value) return 0;

  const mints = txData.value.mints;
  if (!mints) return 0;

  const firstMint = mints[mints.length - 1];
  if (!firstMint) {
    return 0;
  }
  let initToken0 = parseFloat(firstMint.amount0);
  let initToken1 = parseFloat(firstMint.amount1);

  if (firstMint.pair.token0.symbol === baseTokenName.value) {
    return (initToken0 / initToken1) * price.value;
  } else if (firstMint.pair.token1.symbol === baseTokenName.value) {
    return (initToken1 / initToken0) * price.value;
  } else {
    return null;
  }
})


// const checkAddrInput = () => {
//   if (addressInput.value.length === 42) {
//     router.push(`/address/${addressInput.value}`);
//     router.go(0);
//   }
// }

// const toggleMode = () => {
//   detailed.value = !detailed.value;
// }

// const addrShort = (addr: string) => {
//   if (addr.length !== 42) {
//     return null;
//   }
//   let lower = addr.toLowerCase();
//   return `${lower.slice(0, 6)}...${lower.slice(38, 42)}`;
// }

const updatePools = async () => {
  // const em = useProvider(props.provider);
  // const pairInfo = await em.getPairInfo(props.pairAddress);
  // pool0.value = pairInfo.value.reserve0;
  // pool1.value = pairInfo.value.reserve1;
}

const getData = async () => {

  updatePools()

  // Developing
  // use getTxInfo(pairAddress)

  // Use: info.uniswap.org
  
  if (!pairInfo.value) {
    throw "pairInfo not init"
  }
  
  const res = await getTxByPair(pairInfo.value.id, props.graphql);


  if (res && txData.value) {
    const newFirst = res.swaps[0];
    const oldFirst = txData.value.swaps[0];
    if (newFirst.transaction.timestamp < oldFirst.transaction.timestamp) {
      console.log("aborted!");
      return;
    }
  }

  txData.value = await new DataBuilder(res).useConfigPluginList().build();

  if (!txData.value) {
    throw "txData not init"
  }
  const swaps = txData.value.swaps;
  const mints = txData.value.mints;
  const burns = txData.value.burns;

  t0FlowWhiteList.value = 0;
  t1FlowWhiteList.value = 0;
  t1FlowIn.value = 0;
  t1FlowOut.value = 0;
  t0FlowIn.value = 0;
  t0FlowOut.value = 0;

  swaps.map((item: any) => {
    t1FlowIn.value += parseFloat(item.amount1In);
    t1FlowOut.value += parseFloat(item.amount1Out);
    t0FlowIn.value += parseFloat(item.amount0In);
    t0FlowOut.value += parseFloat(item.amount0Out);
    if (WHITELIST.includes(item.to)) {
      t0FlowWhiteList.value += parseFloat(item.amount0In);
      t0FlowWhiteList.value -= parseFloat(item.amount0Out);
      t1FlowWhiteList.value += parseFloat(item.amount1In);
      t1FlowWhiteList.value -= parseFloat(item.amount1Out);
    }
  });

  mints.map((item: any) => {
    t1FlowIn.value += parseFloat(item.amount1);
    t0FlowIn.value += parseFloat(item.amount0);
    if (WHITELIST.includes(item.to)) {
      t0FlowWhiteList.value += parseFloat(item.amount0);
      t1FlowWhiteList.value += parseFloat(item.amount1);
    }
  });

  burns.map((item: any) => {
    t1FlowOut.value += parseFloat(item.amount1);
    t0FlowOut.value += parseFloat(item.amount0);
    if (WHITELIST.includes(item.sender)) {
      t0FlowWhiteList.value -= parseFloat(item.amount0);
      t1FlowWhiteList.value -= parseFloat(item.amount1);
    }
  });
}

onMounted(async () => {
  // init contract
  const tList = [] as Date[]
  const showDt = () => {
    tList.push(new Date())
    const t1 = tList[tList.length-1]
    const t0 = tList[tList.length-2]
    console.log(`use: ${(t1.valueOf() - t0.valueOf()) / 1000}`);
  }

  tList.push(new Date())
  const em = useProvider(props.provider);
  showDt()

  // heavy
  pairInfo.value = await em.getPairInfo(props.pairAddress);
  showDt()
  token0.value = pairInfo.value.token0;
  token1.value = pairInfo.value.token1;
  pool0.value = parseFloat(pairInfo.value.reserve0);
  pool1.value = parseFloat(pairInfo.value.reserve1);
  token0Addr.value = pairInfo.value.token0Addr;
  token1Addr.value = pairInfo.value.token1Addr;

  // Set ETH Price

  // heavy
  price.value = await usePrice(baseTokenName.value, "CNY");
  showDt()
  price_usd.value = await usePrice(baseTokenName.value, "USD");
  showDt()
  await getData();
  showDt()

  setInterval(() => {
    getData();
  }, 10000);
})


watch(txData, (newVal, oldVal) => {
  if (!oldVal || !newVal || oldVal.swaps.length === 0) {
    return;
  }
  const oldTrans = oldVal.swaps[0].transaction.id;
  const newTrans = newVal.swaps[0].transaction.id;

  const newAcc = (newVal.swaps[0].to || newVal.swaps[0].sender) as string;
  if (oldTrans != newTrans && !WHITELIST.includes(newAcc)) {
    audioRef.play();
    console.log("new transaction detected");
  }
}, {
  immediate: true,
  deep: true,
})

watch(txData, (val) => {
  console.log(val)
})

// watch(addressInputShow, (newVal, oldVal => {
//   if (newVal === true) {
//     setTimeout(() => {
//       $refs["addrInput"].focus();
//     }, 50);
//   }
// })

</script>

<template>
  <div class="monitor" :style="{ background: theme.getColor(2) }">
    <!-- Loading -->
    <Loading v-if="!txData" />

    <!-- Main -->
    <div class="monitor-data-wrapper" v-if="txData">
      <div class="align-items-baseline mb-3" :style="themeManager.paneStyle()">
        <span class="h2" role="button">{{ token0 }}-{{ token1 }}</span>
        <a
          :href="scan + '/address/' + tokenAddress"
          class="ml-1 d-none d-lg-inline"
          target="_blank"
        >{{ tokenAddress }}</a>
      </div>

      <!-- Detail mode -->
      <!-- <div class="mb-3" v-show="detailed" :style="$root.themeManager.paneStyle()">
        <div>
          <span>Pool {{ token0 }}:</span>
          <span>{{ pool0 }}</span>
        </div>
        <div>
          <span>Flow {{ token0 }}:</span>
          <span>{{ t0Flow }}</span>
        </div>
        <div style="padding-left: 16px">
          <span>- FlowIn {{ token0 }}:</span>
          <span>{{ t0FlowIn }}</span>
        </div>
        <div style="padding-left: 16px">
          <span>- FlowOut {{ token0 }}:</span>
          <span>{{ t0FlowOut }}</span>
        </div>
      </div>

      <div class="mb-3" :style="$root.themeManager.paneStyle()" v-show="detailed">
        <div>
          <span>Pool {{ token1 }}:</span>
          <span>{{ pool1 }}</span>
        </div>
        <div>
          <span>Flow {{ token1 }}:</span>
          <span>{{ t1Flow }}</span>
        </div>
        <div style="padding-left: 16px">
          <span>- FlowIn {{ token1 }}:</span>
          <span>{{ t1FlowIn }}</span>
        </div>
        <div style="padding-left: 16px">
          <span>- FlowIn {{ token1 }}:</span>
          <span>{{ t1FlowOut }}</span>
        </div>
      </div>

      <div class="mb-3" :style="$root.themeManager.paneStyle()" v-show="detailed">
        <div>
          <span>Flow {{ token0 }} (Whitelist): </span>
          <span>{{ t0FlowWhiteList }}</span>
        </div>
        <div>
          <span>Flow {{ token1 }} (Whitelist): </span>
          <span>{{ t1FlowWhiteList }}</span>
        </div>
      </div>

      <div class="mb-3" :style="$root.themeManager.paneStyle()" v-show="detailed">
        <div>
          <span>Flow {{ token0 }} (Filted): </span>
          <span>{{ t0Flow - t0FlowWhiteList }}</span>
          <span v-show="token0 == 'ETH'"
            >≈ ￥{{ (t0Flow - t0FlowWhiteList) * price }}</span
          >
        </div>
        <div>
          <span>Flow {{ token1 }} (Filted): </span>
          <span>{{ t1Flow - t1FlowWhiteList }}</span>
          <span v-show="token1 == 'ETH'"
            >≈ ￥{{ (t1Flow - t1FlowWhiteList) * price }}</span
          >
        </div>
      </div>

      <div class="mb-3" :style="$root.themeManager.paneStyle()">
        <div>
          <span>Gain {{ token0 }}:</span>
          <span>{{ pool0 - t0FlowWhiteList }}</span>
          <span v-show="token0 == 'ETH'"
            >≈ ￥{{ (pool0 - t0FlowWhiteList) * price }}</span
          >
        </div>

        <div>
          <span>Gain {{ token1 }}: </span>
          <span>{{ pool1 - t1FlowWhiteList }}</span>
          <span v-show="token1 == 'ETH'"
            >≈ ￥{{ (pool1 - t1FlowWhiteList) * price }}</span
          >
        </div>
      </div>-->

      <!-- Concise mode -->
      <div class="mb-3" :style="themeManager.paneStyle()" v-show="!detailed">
        <div>
          <span class="mr-2">{{ baseTokenName }} Number:</span>
          <span v-show="token0 == baseTokenName">{{ pool0 }}</span>
          <span v-show="token1 == baseTokenName">{{ pool1 }}</span>
        </div>
        <div>
          <span class="mr-2">{{ baseTokenName == token0 ? token1 : token0 }} Number:</span>
          <span v-show="token0 == baseTokenName">{{ pool1 }}</span>
          <span v-show="token1 == baseTokenName">{{ pool0 }}</span>
        </div>
        <!-- <div>
          <span class="mr-2">Gain:</span>
          <span v-show="token0 == baseTokenName">
            <span>{{ t0Flow - t0FlowWhiteList }}</span>
            <span>≈ ￥{{ (t0Flow - t0FlowWhiteList) * price }}</span>
          </span>
          <span v-show="token1 == baseTokenName">
            <span>{{ t1Flow - t1FlowWhiteList }}</span>
            <span> ≈ ￥{{ (t1Flow - t1FlowWhiteList) * price }} </span>
          </span>
        </div>-->

        <div>
          <span class="mr-1">Price: ¥</span>
          <span class="mr-1">{{ (poolPrice || 0).toFixed(8) }}</span>
          <span class="mr-1">$ {{ (poolPriceUSD || 0).toFixed(8) }}</span>
          <span
            :class="{
              'color-up': poolPrice !== null && initPrice !== null && poolPrice > initPrice,
              'color-down': poolPrice !== null && initPrice !== null && initPrice > poolPrice,
            }"
          >
            <span v-show="poolPrice !== null && initPrice !== null && poolPrice > initPrice">+</span>
            <span>
              {{
                ((((poolPrice || 0) - (initPrice || 0)) / (initPrice || 0)) * 100 || 0).toFixed(2)
              }}%
            </span>
          </span>
        </div>
      </div>

      <!-- Audio -->
      <audio ref="audioRef" :src="audioSrc"></audio>

      <!-- Tabs -->
      <div class="tab-list mb-3" :style="themeManager.paneStyle()">
        <div
          class="tab-item"
          v-for="(item, index) in TABS"
          :key="index"
          :class="{
            'btn-active': index === tabIndex,
            'btn-inactive': index !== tabIndex,
          }"
          @click="tabIndex = index"
        >
          {{
            ({
              Swaps0In:
                (token0 == baseTokenName ? `Buy ${token1}` : `Sell ${token0}`) +
                ` (${swaps0In.length})`,
              Swaps1In:
                (token1 == baseTokenName ? `Buy ${token0}` : `Sell ${token1}`) +
                ` (${swaps1In.length})`,
              All: `All (${swaps.length + adds.length + removes.length})`,
              Swaps: `Swaps (${swaps.length})`,
              Adds: `Adds (${adds.length})`,
              Removes: `Removes (${removes.length})`,
            } as any)[item] || item
          }}
        </div>
      </div>

      <!-- Table -->
      <div class="mb-3 p-0" :style="themeManager.paneStyle()">
        <table class="table-g text-nowrap">
          <thead>
            <tr>
              <th scope="col">Flow</th>
              <th scope="col" class="text-right">Token Amount</th>
              <th scope="col" class="text-right">Token Amount</th>
              <th scope="col" class="text-right">Account</th>
              <th scope="col" class="text-right">Time</th>
              <th scope="col" class="text-center">Type</th>
            </tr>
          </thead>
          <tbody>
            <tr v-for="(item, index) in list" :key="index">
              <td :style="tdStyle" scope="col">
                <a
                  :class="{
                    'color-up':
                      item.swapName.startsWith('swap') &&
                      !item.swapName.endsWith(' ' + baseTokenName),
                    'color-down':
                      item.swapName.startsWith('swap') &&
                      item.swapName.endsWith(' ' + baseTokenName),
                  }"
                  :href="scan + '/tx/' + item.transaction.id"
                  target="_blank"
                  class="table-a"
                >{{ item.swapName }}</a>
              </td>
              <td :style="tdStyle" scope="col" class="text-right">{{ item.tokenCol0 }}</td>
              <td :style="tdStyle" scope="col" class="text-right">{{ item.tokenCol1 }}</td>
              <td :style="tdStyle" scope="col" class="text-right">
                <a class="text-monospace" :href="scan + '/address/' + item.account" target="_blank">
                  {{
                    `${item.account.slice(0, 6)}...${item.account.slice(
                      38,
                      42
                    )}`
                  }}
                </a>
              </td>

              <td :style="tdStyle" scope="col" class="text-right">{{ item.time }}</td>
              <td :style="tdStyle" scope="col" class="text-center">
                <span
                  title="This address is UniswapV2Router02."
                  v-if="
                    item.account ===
                    '0x7a250d5630b4cf539739df2c5dacb4c659f2488d'
                  "
                >🦄</span>
                <span v-else>
                  <span
                    class="ml-1"
                    title="This address is a contract."
                    v-show="item.isContract"
                    role="button"
                  >👾</span>
                  <span
                    class="ml-1"
                    title="This address is not in the whitelist."
                    v-show="item.outerAccount"
                    role="button"
                  >✅</span>
                  <span
                    class="ml-1"
                    title="This address is in the blacklist."
                    v-show="item.isBlacklist"
                  >🎯</span>
                </span>
              </td>
            </tr>
          </tbody>
        </table>
      </div>
    </div>
  </div>
</template>


<style scoped>
/* border c */
:root {
  /* --color-2: #2a304e; */
  --color-3: #373f63;
}

/* $np-shadow: 0 0 13px #00000055; */
/* $np-shadow-little: 0 0 30px #272d49; */

/* text override */
.btn,
.table {
  color: #cbd4ff;
}
.monitor {
  height: calc(100vh - 49px);
  overflow: auto;
  flex: 1;
  padding: 1rem;
}

.monitor-data-wrapper {
  width: 100%;
}

.title {
  font-size: 2rem;
  font-weight: lighter;
  user-select: none;
  cursor: pointer;
}

.tab-list {
  display: flex;
  width: fit-content;
}

.tab-item {
  padding: 0.5rem 1.5rem;
  user-select: none;
  cursor: pointer;
}

.btn-inactive {
  background-color: #00000000;
}
.btn-inactive:hover {
  background-color: #00000080;
}
.btn-active {
  background-color: #00000040;
}

.table th {
  border: none;
}

.addrInput {
  outline: none;
  background-color: #00000000;
  border: none;
  border-bottom: 1px solid var(--color-3);
  color: #000;
  text-align: center;
}

.table-g {
  width: 100%;
  margin-bottom: 1rem;
}

.table-g thead th {
  vertical-align: bottom;
}
.table-g td,
.table-g th {
  padding: 0.75rem;
  vertical-align: top;
  border-top: 1px solid #dee2e6;
}
.table-g th {
  border: none;
}

.color-up {
  color: #00b464;
}
.color-down {
  color: #fa4d56;
}
</style>
